home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / master / Examples / Visual / VOpts / command.c next >
Encoding:
C/C++ Source or Header  |  1994-02-01  |  29.2 KB  |  991 lines

  1. #include "vopts.h"
  2.  
  3. Prototype void do_command(char *string);
  4. Prototype void read_file(int type);
  5. Prototype void save_file(int type);
  6. Prototype int get_filename(char *str);
  7. Prototype void reset_options(int reshow);
  8. Prototype void reset_group(struct G_OBJECT *object);
  9. Prototype int match_opt(char *optstr,char **valstr,char *buf, int exact);
  10. Prototype int set_option(struct G_OBJECT *object,char **argv, int exact);
  11. Prototype int parse_options(char *string);
  12. Prototype int get_option(struct G_OBJECT *object, char **buf, int *len);
  13. Prototype int append_option(char *optstr1, char *optstr2, char **buf, int *len);
  14.  
  15. parse_options(char *string);
  16.  
  17. /***********************************************************************************
  18.  * Procedure: do_command
  19.  * Synopsis:  do_command(string);
  20.  * Purpose:   Execute the command associated with a given string
  21.  ***********************************************************************************/
  22. void do_command(char *string)
  23. {
  24.    char *p;
  25.    char buf[10];
  26.    int len;
  27.    int type;
  28.  
  29.    /* The following valid commands are allowed: */
  30.    /*    READ  [ file | ? | ENV ]               */
  31.    /*    SAVE  [ file | ? | ENV ]               */
  32.    /*    RESET                                  */
  33.    /*    QUIT                                   */
  34.    /*    PARSE option                           */
  35.  
  36.    len = 0;
  37.    while (*string == ' ') string++;
  38.  
  39.    p = string;
  40.    while(((*p >= 'A') && (*p <= 'Z')) ||
  41.          ((*p >= 'a') && (*p <= 'z')))
  42.    {
  43.       if (*p < 'Z') /* Upper case characters which occur first in ASCII */
  44.          buf[len++] = *p;
  45.       else
  46.          buf[len++] = 'A' + (*p - 'a');
  47.       if (len > 5) break;
  48.       p++;
  49.    }
  50.    buf[len] = 0;
  51.    while(*p == ' ') p++;
  52.  
  53.    if (!strcmp(buf, "READ"))
  54.    {
  55.       global.fileop = 0;
  56.       type = get_filename(p);
  57.       if (type == 0)            /* user aborted filename                */
  58.          return;
  59.       SetWindowTitles(global.window, global.title, global.wtitle);
  60.       global.filetype = type;
  61.       read_file(type);
  62.    }
  63.    else if (!strcmp(buf, "SAVE"))
  64.    {
  65.       global.fileop = 1;
  66.       type = get_filename(p);
  67.       if (type == 0)            /* user aborted filename                */
  68.          return;
  69.       if (request(0, TEXT_SAVEOK, global.filename, NULL) == 0)
  70.          /* Chickened out...    */
  71.          return;
  72.       SetWindowTitles(global.window, global.title, global.wtitle);
  73.       global.filetype = type;
  74.       save_file(type);
  75.    }
  76.    else if (!strcmp(buf, "QUIT"))
  77.    {
  78.       global.done = 1;
  79.    }
  80.    else if (!strcmp(buf, "PARSE"))
  81.    {
  82.       char tbuf[MAX_STRING+1];
  83.       strncpy(tbuf, p, MAX_STRING);
  84.       set_gadgets(0);
  85.       parse_options(tbuf);
  86.       set_gadgets(1);
  87.    }
  88.    else if (!strcmp(buf, "RESET"))
  89.    {
  90.       reset_options(1);
  91.    }
  92.    else
  93.    {
  94.       /* We have an invalid option, ignore the command and let them know  */
  95.       /* about the problem with the option.                               */
  96.       request(1, TEXT_BADCMD, buf, NULL);
  97.       return;
  98.    }
  99. }
  100. /***********************************************************************************
  101.  * Procedure: read_file
  102.  * Synopsis:  read_file(type)
  103.  * Purpose:   read file, extract options according to (type) and display
  104.  ***********************************************************************************/
  105. void read_file(int type)
  106. {
  107.    char buf[256];
  108.  
  109.    if (type == FILE_ENV)
  110.    {
  111.       strncpy(buf, getenv("DCCOPTS"), 255);
  112.       reset_options(0);
  113.       parse_options(buf);
  114.    }
  115.    else
  116.    {
  117.       FILE *fp;
  118.       int cstate;
  119.  
  120.       fp = fopen(global.filename, "r");
  121.       if (fp == NULL)
  122.       {
  123.          request(1, TEXT_BADFILE, global.filename, NULL);
  124.          return;
  125.       }
  126.  
  127.       reset_options(0);
  128.       cstate = 1;
  129.       while(cstate && (fgets(buf, 256, fp) != NULL))
  130.       {
  131.          int len;
  132.          int extend;
  133.  
  134.          len = strlen(buf)-1;
  135.          if (len < 2) continue;
  136.  
  137.          buf[len] = 0; /* Wipe out the \n */
  138.          extend = 0;
  139.          if (buf[len-1] == '\\')
  140.          {
  141.             extend = 1;
  142.             buf[--len] = 0;
  143.          }
  144.  
  145.          switch(type)
  146.          {
  147.             case FILE_C:
  148.                /* Make sure it says #pragma DCCOPTS */
  149.                if (!memcmp(buf, "#pragma DCCOPTS ", 16))
  150.                {
  151.                   /* We actually got it */
  152.                   if (cstate == 3)
  153.                   {
  154.                      request(1, TEXT_EXTRAPRG, NULL, NULL);
  155.                      cstate = 0;
  156.                   }
  157.                   else
  158.                   {
  159.                      if (parse_options(buf+16))
  160.                         cstate = 0;
  161.                      else
  162.                         cstate = 2;
  163.                   }
  164.                }
  165.                else
  166.                {
  167.                   if (cstate == 2) cstate = 3;
  168.                }
  169.                break;
  170.             case FILE_OPTIONS:
  171.                cstate = !parse_options(buf);
  172.                break;
  173.             case FILE_DMAKEFILE:
  174.                if ((!memcmp(buf, "CFLAGS=", len=7)) ||
  175.                    (len = 0, cstate == 2))
  176.                {
  177.                   cstate = 0;
  178.                   if (extend) cstate = 2;
  179.                   if (parse_options(buf+len))
  180.                      cstate = 0;
  181.                }
  182.                break;
  183.          }
  184.       }
  185.    global.nameoffile = 1; /* indicate that global.filename has been read in */
  186.    fclose(fp);
  187.    }
  188.    set_gadgets(1);
  189. }
  190.  
  191. /***********************************************************************************
  192.  * Procedure: save_file
  193.  * Synopsis:  save_file(type)
  194.  * Purpose:   Write user selected options to file, formatted for type
  195.  ***********************************************************************************/
  196. void save_file(int type)
  197. {
  198. #define MAXOPTSTR 512
  199.  
  200.    char buf[MAXOPTSTR];
  201.    char *pbuf=buf;
  202.    struct G_GROUP *group;
  203.    int  ok, len = MAXOPTSTR - 1;
  204.  
  205.    *buf = 0;    /* just in case no options are set                      */
  206.  
  207.    if (ok = get_option(global.objects, &pbuf, &len)) /* didn't over run buffer...*/
  208.       for (group = global.groups;
  209.            ok  && (group != NULL);
  210.            group = (struct G_GROUP *)group->base.next)
  211.          {
  212.          if (!((type == FILE_ENV) && group->local))
  213.             ok = get_option(group->objects, &pbuf, &len);
  214.          }
  215.    if (!ok)
  216.       {
  217.       ok = request(0, TEXT_BIGOPTS, NULL, NULL);
  218.       if (!ok) return;
  219.       }
  220. #ifdef JGM_DBG
  221. printf("Options: %s\n", buf);
  222. #endif
  223.  
  224.    if (*buf == 0) return;       /* let's not try anything fancy         */
  225.  
  226.    if (type == FILE_ENV)
  227.    {
  228.       setenv("DCCOPTS", buf);
  229.    }
  230.    else
  231.    {
  232.  
  233.       FILE *fpout, *fpin;
  234.  
  235.       if (global.nameoffile != 1)
  236.       {
  237.          /* didn't already read this file - does it exist? */
  238.          fpin = fopen(global.filename, "r");
  239.          /* yes I know lock is more efficient ... */
  240.          if (fpin != NULL)
  241.          {
  242.             fclose(fpin); /* it don't have nothing we want */
  243.             ok = request(0, TEXT_OVWRITEOK, global.filename, NULL);
  244.             if (!ok) return;
  245.          }
  246.       }
  247.  
  248.       switch (type)
  249.       {
  250.          case FILE_OPTIONS:
  251.          {
  252.             char *p1 = buf, *p2;
  253.  
  254.             fpout = fopen(global.filename, "w");
  255.             if (fpout == NULL)
  256.             {
  257.                request(1, TEXT_BADFILE, global.filename, NULL);
  258.                return;
  259.             }
  260.  
  261.             do
  262.             {
  263.                p2 = strchr(p1+1, '-');
  264.                if (p2 != NULL)
  265.                   p2[-1] = '\0';
  266.                fputs(p1, fpout);
  267.                fputc('\n', fpout);
  268.                p1 = p2;
  269.             }
  270.             while (p1 != NULL);
  271.             fclose(fpout);
  272.             break;
  273.          }
  274.          case FILE_DMAKEFILE:
  275.          {
  276.             int werr = 1;       /* init to no error                     */
  277.             char newname[MAX_FILENAME+11];
  278.             char copybuf[256];
  279.  
  280.             strcpy(newname, global.filename);
  281.             strcat(newname, ".vopt-temp");
  282.             if ((fpin = fopen(newname, "r")) != NULL)
  283.             {
  284.                fclose(fpin);
  285.                remove(newname);
  286.             }
  287.             if (rename(global.filename, newname) < 0)   /* error        */
  288.             {
  289.                request(1, TEXT_NORENAME, global.filename, NULL);
  290.                return;
  291.             }
  292.             if ((fpin = fopen(newname, "r")) == NULL)
  293.             {
  294.                rename(newname, global.filename);
  295.                request(1, TEXT_NOREAD, global.filename, NULL);
  296.                return;
  297.             }
  298.             if ((fpout = fopen(global.filename, "w")) == NULL)
  299.             {
  300.                fclose(fpin);
  301.                rename(newname, global.filename);
  302.                request(1, TEXT_BADFILE, global.filename, NULL);
  303.                return;
  304.             }
  305.  
  306.             /* note that both fprintf() and fputs() return <0 for error */
  307.             while ((fgets(copybuf, 256, fpin) != NULL) && (werr >= 0))
  308.             {
  309.                if (!memcmp(copybuf, "CFLAGS=", 7))
  310.                   werr = fprintf(fpout, "%s%s\n", "CFLAGS= ", buf);
  311.                else
  312.                   werr = fputs(copybuf, fpout);
  313.             }
  314.             fclose(fpout);
  315.             fclose(fpin);
  316.             if (werr < 0)       /* error writing file - don't rename    */
  317.             {
  318.                request(1, TEXT_NOWRITE, newname, NULL);
  319.                remove(global.filename);
  320.                rename(newname, global.filename);
  321.                return;
  322.             }
  323.             remove(newname); /*delete backup copy of file */
  324.             break;
  325.          }
  326.          case FILE_C:
  327.          {
  328.             int werr = 1;   /* init to no error                 */
  329.             int cstate = 0; /* -1 = #pragma DCCOPTS
  330.                                 0 = ordinary line
  331.                                 1 = comment continuation
  332.                             */
  333.             char newname[MAX_FILENAME+11];
  334.             char copybuf[256];
  335.  
  336.             strcpy(newname, global.filename);
  337.             strcat(newname, ".vopt-temp");
  338.             if ((fpin = fopen(newname, "r")) != NULL)
  339.             {
  340.                fclose(fpin);
  341.                remove(newname);
  342.             }
  343.             if (rename(global.filename, newname) < 0)   /* error        */
  344.             {
  345.                request(1, TEXT_NORENAME, global.filename, NULL);
  346.                return;
  347.             }
  348.             if ((fpin = fopen(newname, "r")) == NULL)
  349.             {
  350.                rename(newname, global.filename);
  351.                request(1, TEXT_NOOVWRITE, global.filename, NULL);
  352.                return;
  353.             }
  354.             if ((fpout = fopen(global.filename, "w")) == NULL)
  355.             {
  356.                fclose(fpin);
  357.                rename(newname, global.filename);
  358.                request(1, TEXT_BADFILE, global.filename, NULL);
  359.                return;
  360.             }
  361.  
  362.             werr = fprintf(fpout, "%s%s\n", "#pragma DCCOPTS ", buf);
  363.             while ((fgets(copybuf, 256, fpin) != NULL) && (werr >= 0))
  364.             {
  365.                if (cstate == 0)
  366.                {
  367.                   if (!memcmp(copybuf, "#pragma DCCOPTS ", 16))
  368.                      cstate = -1;
  369.                   else
  370.                   ;
  371.                }
  372.                /* else check for close comment                          */
  373.  
  374.                if (cstate >= 0)
  375.                   werr = fputs(copybuf, fpout);
  376.                else
  377.                   cstate = 0;   /* next line is ordinary - not comment  */
  378.             }
  379.  
  380.             fclose(fpout);
  381.             fclose(fpin);
  382.             if (werr < 0)       /* error writing file - don't rename    */
  383.             {
  384.                request(1, TEXT_NOOVWRITE, newname, NULL);
  385.                remove(global.filename);
  386.                rename(newname, global.filename);
  387.                return;
  388.             }
  389.             remove(newname); /*delete backup copy of file */
  390.             break;
  391.          }
  392.          default:
  393.          printf("unimplemented file type %d\n", type);
  394.       }
  395.    }
  396. }
  397.  
  398. /***********************************************************************************
  399.  * Procedure: get_filename
  400.  * Synopsis:  type = get_filename(str)
  401.  * Purpose:   Parse out a file descriptor and return a type for that name
  402.  ***********************************************************************************/
  403. int get_filename(char *str)
  404. {
  405.    char *p;
  406.    int len;
  407.  
  408.    if (*str)
  409.    {
  410.       /* They actually specified a name.  All we need to do is replace the */
  411.       /* current one.  If they specified a '?', then we need to prompt the */
  412.       /* user with the file requester.  We will assume the ASL one for now */
  413.       /* but should have a reasonable fall back one.                       */
  414.       if (!strcmp(str, "?"))
  415.       {
  416.  
  417.          if (global.freq) /* could be ASL or Arp */
  418.          {
  419.             int n;
  420.             if (AslBase != NULL)
  421.             {
  422. /*
  423.                struct TagItem taglist[2];
  424. */
  425.                struct TagItem taglist[5];
  426. #if 0
  427.                taglist[0].ti_Tag = ASL_Hail;
  428.                taglist[0].ti_Data = (ULONG)(v+1);
  429. #endif
  430. /* new */
  431.                /* Pattern to match against project files */
  432.                taglist[0].ti_Tag  = ASL_Pattern;
  433.                taglist[0].ti_Data = (ULONG)"(#?FILE|#?DM#AK#?|#?.DICE)";
  434.  
  435.                taglist[1].ti_Tag  = ASL_File;
  436.                taglist[1].ti_Data = (ULONG)"";
  437.  
  438.                taglist[2].ti_Tag  = ASL_Dir;
  439.                taglist[2].ti_Data = (ULONG)"";
  440.  
  441.  
  442.                taglist[3].ti_Tag = TAG_DONE;
  443.    
  444.                if (!AslRequest( (APTR)global.freq, taglist))
  445.                   return(0);
  446.             }
  447.             else /* must be Arp since we have a requester... */
  448.             {
  449.                if (!ArpFileRequest(global.freq))
  450.                   return (0);
  451.             }   
  452.             n = strlen(global.freq->rf_Dir);
  453.             if (n > 255) n = 255;
  454.             p = global.filename;
  455.             memcpy(p, global.freq->rf_Dir, n);
  456.             p += n;
  457.  
  458.             if ((n > 0) && (p[-1] != ':') && (p[-1] != '/'))
  459.             {
  460.                *p++ = '/';
  461.                n++;
  462.             }
  463.             len = strlen(global.freq->rf_File);
  464.             if ((n + len) > 255) len = 255-n;
  465.             strncpy(p, global.freq->rf_File, len);
  466.             p[len] = 0;
  467.  
  468.             global.nameoffile = 0; /* new name - possibly unsafe to write */
  469.          }
  470.          else
  471.          {
  472.             /* We don't have ASL.LIBRARY, try something else instead */
  473.             set_fr_gadgets(global.filename);
  474.             /* If user hits save button, we'll be back with the name */
  475.             return 0;
  476.  
  477.          }
  478.       }
  479.       else
  480.       {
  481.          strncpy(global.filename, str, MAX_FILENAME);
  482.       }
  483.    }
  484.  
  485.    if (!stricmp(global.filename, "ENV"))
  486.    {
  487.       strcpy(global.title, global.text[TEXT_GLOBOPTS]);
  488.       return(FILE_ENV);
  489.    }
  490.  
  491.    len = strlen(global.filename);
  492.    p = global.filename + strlen(global.filename);
  493.  
  494.    strcpy(global.title, global.text[TEXT_FILEOPTS]);
  495.    strncat(global.title, global.filename, MAX_TITLE);
  496.    global.title[MAX_TITLE] = 0;
  497.  
  498.    if (len < 2)
  499.       return(FILE_OPTIONS);
  500.  
  501.    if ((len >= 7) && (!stricmp(p-7, "DCCOPTS")))
  502.       return(FILE_OPTIONS);
  503.  
  504.    if ((len >= 9) && (!stricmp(p-9, "DMAKEFILE")))
  505.       return(FILE_DMAKEFILE);
  506.  
  507.    if ((len >= 5) && (!stricmp(p-5, ".DICE")))
  508.       return(FILE_DMAKEFILE);
  509.  
  510.    if (!stricmp(p-2, ".H"))
  511.       return(FILE_C);
  512.  
  513.    if (!stricmp(p-2, ".C"))
  514.       return(FILE_C);
  515.  
  516.    return(FILE_OPTIONS);
  517. }
  518.  
  519. /***********************************************************************************
  520.  * Procedure: reset_options
  521.  * Synopsis:  reset_options(reshow)
  522.  * Purpose:   Reset all the options to the default values
  523.  ***********************************************************************************/
  524. void reset_options(int reshow)
  525. {
  526.    struct G_GROUP *group;
  527.  
  528.    set_gadgets(0);
  529.  
  530.    reset_group(global.objects);
  531.    for(group = global.groups; group != NULL;
  532.        group = (struct G_GROUP *)group->base.next)
  533.    {
  534.       reset_group(group->objects);
  535.    }
  536.    if (reshow) set_gadgets(1);
  537. }
  538.  
  539. /***********************************************************************************
  540.  * Procedure: reset_group
  541.  * Synopsis:  reset_group(object)
  542.  * Purpose:   Reset all the options in a group to the default values
  543.  ***********************************************************************************/
  544. void reset_group(struct G_OBJECT *object)
  545. {
  546. #define object_check ((struct G_CHECK *)object)
  547. #define object_list  ((struct G_LIST *)object)
  548. #define object_str   ((struct G_STRING *)object)
  549. #define object_cycle ((struct G_CYCLE *)object)
  550.  
  551.    while(object != NULL)
  552.    {
  553.       switch(object->class)
  554.       {
  555.          case CLASS_STRING:
  556.             object_str->buf[0] = 0;
  557.             break;
  558.          case CLASS_CYCLE:
  559.             {
  560.                struct G_VALUE *val;
  561.  
  562.                val = object_cycle->curval = object_cycle->values;
  563.                while(val != NULL)
  564.                {
  565.                   if (val->string)
  566.                      val->string->buf[0] = 0;
  567.                   val = val->next;
  568.                }
  569.             }
  570.             break;
  571.          case CLASS_LIST:
  572.             {
  573.                struct G_ENTRY *ent;
  574.                ent = object_list->first;
  575.                object_list->first = object_list->top = NULL;
  576.                object_list->string = object_list->maxent = 0;
  577.                while(ent != NULL)
  578.                {
  579.                   struct G_ENTRY *nextent;
  580.  
  581.                   nextent = (struct G_ENTRY *)ent->base.next;
  582.                   free_mem(ent, sizeof(struct G_ENTRY));
  583.                   ent = nextent;
  584.                }
  585.             }
  586.             break;
  587.          case CLASS_CHECK:
  588.             object->state = 0;
  589.             if (!object_check->option1[0]) object->state = 1;
  590.             break;
  591.          default:
  592.             object->state = 0;
  593.             break;
  594.       }
  595.       object = object->next;
  596.    }
  597. #undef object_list
  598. #undef object_str
  599. #undef object_cycle
  600. #undef object_check
  601. }
  602. /***********************************************************************************
  603.  * Procedure: match_opt
  604.  * Synopsis:  rc = match_opt(optstr, argv, buf, exact)
  605.  * Purpose:   Compare a string to see if it matches a given option
  606.  *            If a successful match, return the number of argv entries used.
  607.  *            If exact is specified, do not look for extension strings.
  608.  ***********************************************************************************/
  609. int match_opt(char *optstr,
  610.               char **argv,
  611.               char *buf,
  612.               int exact
  613.              )
  614. {
  615.    char *p;
  616.    int len, olen;
  617.  
  618.    p = strchr(optstr, '%');
  619.    if ((p == NULL) || (buf == NULL))
  620.    {
  621.       /* We have just a plain option.  For it to match, we must have */
  622.       /* a complete match on the characters.                         */
  623.       return(!strcmp(optstr, *argv));
  624.    }
  625.  
  626.    if (exact) return 0; /* not looking for options strings this pass    */
  627.  
  628.    /* Not a plain one.  There are a couple of possibilities:       */
  629.    /*  -opt%s       No space allowed after the option              */
  630.    /*  -opt %s      Space after option is optional                 */
  631.    /*  -opt  %s     Space after option is mandatory.               */
  632.    olen = len = p - optstr;
  633.    while(len && (optstr[len-1] == ' ')) len--;
  634.    if (memcmp(optstr, *argv, len))
  635.       return(0);
  636.  
  637.    /* We know that at least we match the start of the option.  Now we */
  638.    /* Have to get the buffer filled in.                               */
  639.    if ((*argv)[len]) /* We know that the parameter is with this option */
  640.    {
  641.       /* If the space is mandatory, we obviously didn't make a match  */
  642.       if ((olen - len) > 1) return(0);
  643.       strncpy(buf, argv[0]+len, MAX_STRING);
  644.       return(1);
  645.    }
  646.  
  647.    /* Parameter is with the next option */
  648.    /* If the space is not allowed, we didn't get a match */
  649.    if ((olen == len) || (argv[1] == NULL)) return(0);
  650.    strncpy(buf, argv[1], MAX_STRING);
  651.    return(2);
  652. }
  653.  
  654. /***********************************************************************************
  655.  * Procedure: append_option
  656.  * Synopsis:  rc = append_option(optstr, buffer, length)
  657.  * Purpose:   append option to string buffer, update count and pointer
  658.  ***********************************************************************************/
  659. int append_option(char *optstr1, char *optstr2, char **buf, int *len)
  660. {
  661.    int l;
  662.    char *p, *optr;
  663.  
  664.    optr = optstr1;      /* unless we change it to fetch a string        */
  665.    p = strchr(optstr1, '%');
  666.    if ((p != NULL) && (optstr2 != NULL)) /* seems we have a string      */
  667.    {
  668.       l = p - optstr1;
  669.       if (l >= *len) return 0;  /*no room to save it                    */
  670.       if (optstr1[l-1] == ' ')
  671.          l -= 1;
  672.       memcpy(*buf, optstr1, l);
  673.       *buf += l;
  674.       *len -= l;
  675.       **buf = '\0';     /* just in case next step fails...              */
  676.       optr = optstr2;
  677.    }
  678.  
  679.    /* now copy whatever is left and put a blank on the end              */
  680.    l = strlen(optr);
  681.    if (l >= *len) return 0;     /* no room to save it                   */
  682.    strcpy(*buf, optr);
  683.    *buf += l;
  684.    strcpy(*buf, " ");
  685.    *buf += 1;
  686.    *len -= (l + 1);
  687.  
  688.    return 1;
  689. }
  690.  
  691. /***********************************************************************************
  692.  * Procedure: get_option
  693.  * Synopsis:  rc = get_option(object, buffer, length)
  694.  * Purpose:   make a string of all options that are set
  695.  ***********************************************************************************/
  696. int get_option(struct G_OBJECT *object,
  697.                char **buf,
  698.                int *len
  699.               )
  700. {
  701. #define object_list  ((struct G_LIST   *)object)
  702. #define object_str   ((struct G_STRING *)object)
  703. #define object_check ((struct G_CHECK  *)object)
  704. #define object_cycle ((struct G_CYCLE  *)object)
  705.    while (object != NULL)
  706.    {
  707.       switch (object->class)
  708.       {
  709.          case CLASS_CYCLE:
  710.          {
  711.             struct G_VALUE *val;
  712.  
  713.             val = object_cycle->curval;
  714.             if (val->option[0] == 0) break;     /* option not set       */
  715.             if
  716.             (
  717.                 append_option(val->option,
  718.                               val->string != NULL ? val->string->buf : NULL,
  719.                               buf, len)
  720.                 == 0
  721.             )
  722.                return 0;        /* no room to save it                   */
  723.             break;
  724.          }
  725.          case CLASS_CHECK:
  726.          {
  727.             char *p;
  728.             p = object->state ? object_check->option1 : object_check->option0;
  729.             if (*p)             /* do we gots a string?                 */
  730.                if (append_option(p, NULL, buf, len) == 0)
  731.                   return 0;     /* shucks, nowhere to put it            */
  732.             break;
  733.          }
  734.          case CLASS_STRING:
  735.          {
  736.             if (object_str->buf[0] == 0) break; /* empty string         */
  737.             if
  738.             (
  739.                 append_option(object_str->option,
  740.                               object_str->buf,
  741.                               buf, len)
  742.                 == 0
  743.             )
  744.                return 0;        /* no room, buf is full...              */
  745.             break;
  746.          }
  747.          case CLASS_LIST:
  748.          {
  749.             struct G_ENTRY *ent;
  750.  
  751.             ent = object_list->first;
  752.             while (ent != NULL) /* empty list will fall through         */
  753.             {
  754.                if
  755.                (append_option(object_list->option, ent->buf, buf, len) == 0)
  756.                   return 0;     /* seem familiar?                       */
  757.                ent = (struct G_ENTRY *)ent->base.next;
  758.             }
  759.             break;
  760.          }
  761.       }
  762.       object = object->next;
  763.    }
  764.    return 1;
  765. #undef object_check
  766. #undef object_list
  767. #undef object_str
  768. #undef object_cycle
  769. }
  770.  
  771. /***********************************************************************************
  772.  * Procedure: set_option
  773.  * Synopsis:  rc = set_option(object, optstr, exact)
  774.  * Purpose:   Set an option based on a option string, allowing parms if not exact
  775.  ***********************************************************************************/
  776. int set_option(struct G_OBJECT *object,
  777.                char **argv,
  778.                int exact
  779.               )
  780. {
  781.    int used;
  782. #define object_list  ((struct G_LIST   *)object)
  783. #define object_str   ((struct G_STRING *)object)
  784. #define object_check ((struct G_CHECK  *)object)
  785. #define object_cycle ((struct G_CYCLE  *)object)
  786.  
  787.    used = 0;
  788.  
  789.    while((used == 0) && (object != NULL))
  790.    {
  791.       switch(object->class)
  792.       {
  793.          case CLASS_STRING:
  794.             used = match_opt(object_str->option, argv, object_str->buf, exact);
  795.             break;
  796.          case CLASS_CYCLE:
  797.             {
  798.                struct G_VALUE *val;
  799.  
  800.                for(val = object_cycle->values;
  801.                    val != NULL;
  802.                    val = (struct G_VALUE *)val->next)
  803.                {
  804.                   used = match_opt(val->option, argv,
  805.                                    val->string ? val->string->buf : NULL,
  806.                                    exact);
  807.                   if (used)
  808.                   {
  809.                      object_cycle->curval = val;
  810.                      break;
  811.                   }
  812.                }
  813.             }
  814.             break;
  815.          case CLASS_CHECK:
  816.             used = match_opt(object_check->option0, argv, NULL, exact);
  817.             if (used)
  818.             {
  819.                object->state = 0;
  820.             }
  821.             else
  822.             {
  823.                used = match_opt(object_check->option1, argv, NULL, exact);
  824.                if (used)
  825.                {
  826.                   object->state = 1;
  827.                }
  828.             }
  829.             break;
  830.          case CLASS_LIST:
  831.             {
  832.                char buf[MAX_STRING+1];
  833.  
  834.                used = match_opt(object_list->option, argv, buf, exact);
  835.                if (used)
  836.                {
  837.                   struct G_ENTRY *ent, *prevent;
  838.  
  839.                   ent = get_mem(sizeof(struct G_ENTRY));
  840.                   if (ent)
  841.                   {
  842.                      strcpy(ent->buf, buf);
  843.                      if ((prevent = object_list->top) == NULL)
  844.                         object_list->top = object_list->first = ent;
  845.                      else
  846.                      {
  847.                         while(prevent->base.next)
  848.                            prevent = (struct G_ENTRY *)prevent->base.next;
  849.                         prevent->base.next = (struct G_OBJECT *)ent;
  850.                         ent->base.prev = (struct G_OBJECT *)prevent;
  851.                      }
  852.                   }
  853.                }
  854.             }
  855.             break;
  856.          default:
  857.             object->state = 0;
  858.             break;
  859.       }
  860.       object = object->next;
  861.    }
  862.  
  863.    return(used);
  864. #undef object_check
  865. #undef object_list
  866. #undef object_str
  867. #undef object_cycle
  868. }
  869.  
  870. /***********************************************************************************
  871.  * Procedure: parse_options
  872.  * Synopsis:  parse_options(string);
  873.  * Purpose:   Parse an option and set the appropriate options in the global options
  874.  *            data.  This subroutine destroys the string buffer.
  875.  ***********************************************************************************/
  876. #define MAX_BUF 100
  877.  
  878. int parse_options(char *string)
  879. {
  880. #define MAX_ARGS 80
  881.  
  882.    /* First we need to create an ARGV type array */
  883.    /* We will assume no more than 80 arguments in a line */
  884.    char *argv[MAX_ARGS];
  885.    int argc;
  886.    int state;
  887. /*
  888.  * Character Classes:
  889.  *   SQ    '           Single Quote
  890.  *   DQ    "           Double Quote
  891.  *   BL    Space, Tab  White Space
  892.  *   NL    Null        End of the string
  893.  *   OT    Other       Anything else
  894.  *        SQ   DQ   BL   NL   OT
  895.  *    0    1    2    0    x    3
  896.  *    1   >0   +1   +1   >x   +1
  897.  *    2   +2   >0   +2   >x   +2
  898.  *    3   +3   +3   >0   >x   +3
  899.  */
  900. #define SQ 0
  901. #define DQ 1
  902. #define BL 2
  903. #define NL 3
  904. #define OT 4
  905. #define EXI 15
  906. #define STATE_MASK 0x0f
  907. #define ACTION_SHIFT  4
  908. #define ACT_SKP 1
  909. #define ACT_OUT 2
  910. #define ACT_BEG 3
  911. #define SKP (ACT_SKP << ACTION_SHIFT)
  912. #define OUT (ACT_OUT << ACTION_SHIFT)
  913. #define BEG (ACT_BEG << ACTION_SHIFT)
  914.  
  915.    static char class_tab[][5] = {
  916.       { SKP|1, SKP|2,     0,       EXI, BEG|3 },
  917.       { OUT|0,     1,     1,   OUT|EXI,     1 },
  918.       {     2, OUT|0,     2,   OUT|EXI,     2 },
  919.       {     3,     3, OUT|0,   OUT|EXI,     3 }
  920.    };
  921.  
  922.    argc = 0;
  923.    state = 0;
  924.    while(state != EXI)
  925.    {
  926.       int class;
  927.       int look;
  928.  
  929.       switch(*string)
  930.       {
  931.          case '\'': class = SQ; break;
  932.          case '"' : class = DQ; break;
  933.          case ' ' :
  934.          case '\t': class = BL; break;
  935.          case    0: class = NL; break;
  936.          default:   class = OT; break;
  937.       }
  938.       look = class_tab[state][class];
  939.       state = look & STATE_MASK;
  940.       switch(look >> ACTION_SHIFT)
  941.       {
  942.          case ACT_SKP:
  943.             argv[argc++] = string+1;
  944.             break;
  945.          case ACT_OUT:
  946.             *string = 0;
  947.             break;
  948.          case ACT_BEG:
  949.             argv[argc++] = string;
  950.             break;
  951.       }
  952.       string++;
  953.    }
  954.  
  955.    if (argc == 0) return(0);
  956.  
  957.    argv[argc] = NULL;
  958.  
  959.    {
  960.       int i, used, exact;
  961.       struct G_GROUP *group;
  962.  
  963.       for(i = 0; i < argc; i += used)
  964.       {
  965.  
  966.          used = 0;      /* we've used what we used before       */
  967.          /* do exact matches first to find things like -I0      */
  968.          for (exact = 1; (exact >= 0) && (used == 0); exact -= 1)
  969.          {
  970.             used = set_option(global.objects, argv+i, exact);
  971.  
  972.             for(group = global.groups; (used == 0) && (group != NULL);
  973.                 group = (struct G_GROUP *)group->base.next)
  974.             {
  975.                used = set_option(group->objects, argv+i, exact);
  976.             }
  977.          }
  978.          if ((!used) && (exact <= 0))
  979.          {
  980.             /* The option wasn't found, tell them in some way */
  981.             if (!request(0, TEXT_BADOPT, argv[i], NULL))
  982.                return(1);
  983.             else
  984.                used = 1; /* throw away the token and continue */
  985.          }
  986.  
  987.       }
  988.    }
  989.    return(0);
  990. }
  991.